home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
CW GUSI 1.6.4
/
src
/
GUSIPPC.cp
< prev
next >
Wrap
Text File
|
1995-11-05
|
17KB
|
854 lines
/*********************************************************************
Project : GUSI - Grand Unified Socket Interface
File : GUSIPPC.cp - PPC Sockets
Author : Matthias Neeracher
Language : MPW C/C++
$Log: GUSIPPC.cp,v $
Revision 1.4 1994/12/30 20:14:30 neeri
Wake up process from completion procedure.
Revision 1.3 1994/08/10 00:06:01 neeri
Sanitized for universal headers.
Revision 1.2 1994/05/01 23:30:32 neeri
Enable recvfrom with non-NULL from address.
Revision 1.1 1994/02/25 02:30:02 neeri
Initial revision
Revision 0.13 1993/12/30 00:00:00 neeri
Fiddle with select()
Revision 0.12 1993/09/01 00:00:00 neeri
Throw out nonbreaking spaces
Revision 0.11 1993/06/20 00:00:00 neeri
Changed sa_constr_ppc
Revision 0.10 1993/02/07 00:00:00 neeri
New configuration technique
Revision 0.9 1992/12/17 00:00:00 neeri
Forgot to clear errno in PPCSocketDomain::socket()
Revision 0.8 1992/12/06 00:00:00 neeri
Check flags
Revision 0.7 1992/09/13 00:00:00 neeri
Always complete write
Revision 0.6 1992/09/07 00:00:00 neeri
Implement ioctl()
Revision 0.5 1992/08/30 00:00:00 neeri
Move hasPPC here
Revision 0.4 1992/08/10 00:00:00 neeri
Correct select()
Revision 0.3 1992/08/03 00:00:00 neeri
Introduce additional buffering
Revision 0.2 1992/08/03 00:00:00 neeri
Approximately correct, except for sync/async
Revision 0.1 1992/08/02 00:00:00 neeri
Put some further work in
*********************************************************************/
#include "GUSIPPC_P.h"
#include <Errors.h>
#include <ADSP.h>
#include <Devices.h>
#include <GestaltEqu.h>
#include <PLStringFuncs.h>
#include <LowMem.h>
class PPCSocket; // That's what this file's all about
struct PPCPB {
PPCParamBlockRec ppc;
PPCSocket * sock;
};
class PPCSocket : public Socket {
friend class PPCSocketDomain;
friend pascal void PPCReadHellHound(PPCPB * pb);
friend pascal void PPCWriteHellHound(PPCPB * pb);
enum {
notBound,
notOpen,
isListening,
isOpen,
isAccepted} status;
Boolean nonblocking;
Boolean readPending;
Boolean writePending;
Boolean readShutDown;
Boolean writeShutDown;
LocationNameRec location;
PPCPortRec port;
LocationNameRec peerLoc;
PPCPortRec peerPort;
PPCPB pb;
PPCPB * rpb;
RingBuffer * rb;
RingBuffer * wb;
#if !GENERATINGCFM
Ptr processA5; /* Our A5 world */
#endif
PPCSocket();
PPCSocket(const PPCSocket & acceptFrom);
virtual ~PPCSocket();
int Alloc();
void HellHoundsOnMyTrail();
public:
void Ready();
virtual int bind(void * name, int namelen);
virtual int getsockname(void * name, int * namelen);
virtual int getpeername(void *name, int *namelen);
virtual int fcntl(unsigned int cmd, int arg);
virtual int listen(int qlen);
virtual int connect(void * address, int addrlen);
virtual Socket * accept(void * address, int * addrlen);
virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
virtual int shutdown(int how);
virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
virtual int ioctl(unsigned int request, void *argp);
};
PPCSocketDomain PPCSockets;
#if GENERATINGCFM
inline void PPCSocket::Ready()
{
PPCSockets.Ready();
}
#endif
/************************ PPC Toolbox initialization ************************/
pascal OSErr PPCInit_P()
{
OSErr err;
long attr;
if (err = Gestalt(gestaltPPCToolboxAttr, &attr))
return err;
if (!(attr & gestaltPPCSupportsRealTime))
err = PPCInit();
return err;
}
Feature hasPPC(PPCInit_P);
/********************* Link stuffing procedures *********************/
#if !GENERATINGCFM
void PPCSocket::Ready()
{
long saveA5 = SetA5(long(processA5));
PPCSockets.Ready();
SetA5(saveA5);
}
#endif
#if GENERATINGCFM
RoutineDescriptor uPPCReadHellHound =
BUILD_ROUTINE_DESCRIPTOR(uppPPCCompProcInfo, PPCReadHellHound);
#else
#define uPPCReadHellHound PPCReadHellHound
#endif
pascal void PPCReadHellHound(PPCPB * pb)
{
if (!pb->sock->rb) // We're closing
return;
RingBuffer & buf = *pb->sock->rb;
PPCReadPBRec & p = pb->ppc.readParam;
Boolean & pend = pb->sock->readPending;
if (buf.Locked())
buf.Later(Deferred(PPCReadHellHound), pb);
else {
pb->sock->Ready();
buf.Later(nil, nil);
if (pend) {
pend = false;
if (p.ioResult) {
pb->sock->readShutDown = true;
return;
}
buf.Validate(p.actualLength);
}
if (!buf.Free())
buf.Later(Deferred(PPCReadHellHound), pb);
else {
long max = 1000000;
p.ioCompletion = PPCCompUPP(&uPPCReadHellHound);
p.bufferPtr = buf.Producer(max);
p.bufferLength = max;
pend = true;
PPCReadAsync(&p);
}
}
}
#if GENERATINGCFM
RoutineDescriptor uPPCWriteHellHound =
BUILD_ROUTINE_DESCRIPTOR(uppPPCCompProcInfo, PPCWriteHellHound);
#else
#define uPPCWriteHellHound PPCWriteHellHound
#endif
pascal void PPCWriteHellHound(PPCPB * pb)
{
if (!pb->sock->wb) // We're closing
return;
RingBuffer & buf = *pb->sock->wb;
PPCWritePBRec & p = pb->ppc.writeParam;
Boolean & pend = pb->sock->writePending;
if (buf.Locked())
buf.Later(Deferred(PPCWriteHellHound), pb);
else {
pb->sock->Ready();
buf.Later(nil, nil);
if (pend) {
pend = false;
if (p.ioResult) {
pb->sock->writeShutDown = true;
return;
}
buf.Invalidate(p.actualLength);
}
if (!buf.Valid())
buf.Later(Deferred(PPCWriteHellHound), pb);
else {
long max = 1000000;
p.ioCompletion = PPCCompUPP(&uPPCWriteHellHound);
p.bufferPtr = buf.Consumer(max);
p.bufferLength = max;
p.more = false;
p.userData = 0;
p.blockCreator = 'GU∑I';
p.blockType = 'GU∑I';
pend = true;
PPCWriteAsync(&p);
}
}
}
/************************ PPCSocket members ************************/
PPCSocket::PPCSocket()
{
status = PPCSocket::notBound;
nonblocking = false;
pb.sock = this;
rpb = nil;
rb = nil;
wb = nil;
readPending = false;
writePending = false;
readShutDown = false;
writeShutDown = false;
#if !GENERATINGCFM
processA5 = LMGetCurrentA5();
#endif
}
PPCSocket::PPCSocket(const PPCSocket & acceptFrom)
{
status = PPCSocket::isAccepted;
nonblocking = acceptFrom.nonblocking;
pb.ppc = acceptFrom.pb.ppc;
pb.sock = this;
rpb = nil;
rb = nil;
wb = nil;
readPending = false;
writePending = false;
readShutDown = false;
writeShutDown = false;
location = acceptFrom.location;
port = acceptFrom.port;
peerLoc = acceptFrom.peerLoc;
peerPort = acceptFrom.peerPort;
#if !GENERATINGCFM
processA5 = LMGetCurrentA5();
#endif
}
PPCSocket::~PPCSocket()
{
if (rb) {
delete rb;
rb = nil;
}
if (wb) {
delete wb;
wb = nil;
}
switch (status) {
case PPCSocket::isAccepted:
PPCEndSync(&pb.ppc.endParam);
break; // Don't close the port
case PPCSocket::isListening:
case PPCSocket::isOpen:
PPCEndSync(&pb.ppc.endParam);
/* Fall through */
case PPCSocket::notOpen:
PPCCloseSync(&pb.ppc.closeParam);
/* Fall through */
case PPCSocket::notBound:
break;
}
}
int PPCSocket::Alloc()
{
if (!rpb)
rpb = new PPCPB;
if (!rpb)
goto error;
rpb->sock = this;
if (!rb)
rb = new RingBuffer(2048);
if (!rb)
goto error;
if (!*rb)
goto errRB;
if (!wb)
wb = new RingBuffer(2048);
if (!wb)
goto errRB;
if (!*wb)
goto errWB;
return 0;
errWB:
delete wb;
wb = nil;
errRB:
delete rb;
rb = nil;
error:
return GUSI_error(ENOMEM);
}
void PPCSocket::HellHoundsOnMyTrail()
{
rpb->ppc.readParam.sessRefNum = pb.ppc.startParam.sessRefNum;
PPCReadHellHound(rpb);
PPCWriteHellHound(&pb);
}
int PPCSocket::fcntl(unsigned int cmd, int arg)
{
switch (cmd) {
case F_GETFL:
if (nonblocking)
return FNDELAY;
else
return 0;
case F_SETFL:
if (arg & FNDELAY)
nonblocking = true;
else
nonblocking = false;
return 0;
default:
return GUSI_error(EOPNOTSUPP);
}
}
int PPCSocket::ioctl(unsigned int request, void *argp)
{
switch (request) {
case FIONBIO:
nonblocking = (Boolean) *(long *) argp;
return 0;
case FIONREAD:
switch(status) {
case PPCSocket::isAccepted:
case PPCSocket::isOpen:
break;
default:
return GUSI_error(ENOTCONN);
}
*(unsigned long *) argp = rb->Valid();
return 0;
default:
return GUSI_error(EOPNOTSUPP);
}
}
int PPCSocket::bind(void *sa_name, int)
{
struct sockaddr_ppc * addr = (struct sockaddr_ppc *) sa_name;
if (addr->family != AF_PPC)
GUSI_error(EAFNOSUPPORT);
if (status != PPCSocket::notBound)
return GUSI_error(EINVAL);
location = addr->location;
port = addr->port;
pb.ppc.openParam.ioCompletion = nil;
pb.ppc.openParam.serviceType = ppcServiceRealTime;
pb.ppc.openParam.resFlag = 0;
pb.ppc.openParam.portName = &port;
pb.ppc.openParam.locationName = &location;
pb.ppc.openParam.networkVisible = true;
switch (PPCOpenSync(&pb.ppc.openParam)) {
case noErr:
break;
case nameTypeErr:
case badReqErr:
case badPortNameErr:
case badLocNameErr:
return GUSI_error(EINVAL);
case noGlobalsErr:
return GUSI_error(ENOMEM);
case portNameExistsErr:
case nbpDuplicate:
return GUSI_error(EADDRINUSE);
default:
return GUSI_error(EINVAL);
}
status = PPCSocket::notOpen;
return 0;
}
int PPCSocket::getsockname(void *name, int *namelen)
{
struct sockaddr_ppc addr;
addr.family = AF_PPC;
addr.location = location;
addr.port = port;
memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(struct sockaddr_ppc))));
return 0;
}
int PPCSocket::getpeername(void *name, int *namelen)
{
struct sockaddr_ppc addr;
addr.family = AF_PPC;
addr.location = peerLoc;
addr.port = peerPort;
memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(struct sockaddr_ppc))));
return 0;
}
int PPCSocket::listen(int)
{
switch (status) {
case PPCSocket::notBound:
return GUSI_error(EINVAL);
case PPCSocket::isOpen:
case PPCSocket::isListening:
return GUSI_error(EISCONN);
default:
break;
}
pb.ppc.informParam.autoAccept = true;
pb.ppc.informParam.portName = &peerPort;
pb.ppc.informParam.locationName = &peerLoc;
pb.ppc.informParam.userName = nil;
if (PPCInformAsync(&pb.ppc.informParam))
return GUSI_error(EINVAL);
status = PPCSocket::isListening;
return 0;
}
int PPCSocket::connect(void *sa_name, int)
{
Boolean guest;
struct sockaddr_ppc * addr = (struct sockaddr_ppc *) sa_name;
Str32 uname;
switch (status) {
case PPCSocket::notBound:
return GUSI_error(EINVAL);
case PPCSocket::isOpen:
case PPCSocket::isListening:
case PPCSocket::isAccepted:
return GUSI_error(EISCONN);
default:
break;
}
if (Alloc())
return -1;
if (addr->family != AF_PPC)
GUSI_error(EAFNOSUPPORT);
peerLoc = addr->location;
peerPort = addr->port;
uname[0] = 0;
pb.ppc.startParam.serviceType = ppcServiceRealTime;
pb.ppc.startParam.resFlag = 0;
pb.ppc.startParam.portName = &peerPort;
pb.ppc.startParam.locationName = &peerLoc;
pb.ppc.startParam.userData = 0;
if (StartSecureSession(&pb.ppc.startParam, uname, true, true, &guest, (StringPtr) "\p"))
return GUSI_error(EINVAL);
status = PPCSocket::isOpen;
HellHoundsOnMyTrail();
return 0;
}
Socket * PPCSocket::accept(void * address, int * addrlen)
{
PPCSocket * newsock;
if (status != PPCSocket::isListening)
return (Socket *) GUSI_error_nil(ENOTCONN);
if (nonblocking && pb.ppc.informParam.ioResult == 1)
return (Socket *) GUSI_error_nil(EWOULDBLOCK);
SPINP(pb.ppc.informParam.ioResult == 1, SP_MISC, 0);
if (pb.ppc.informParam.ioResult)
return (Socket *) GUSI_error_nil(EINVAL);
newsock = new PPCSocket(*this);
if (!newsock)
return (Socket *) GUSI_error_nil(ENOMEM);
if (newsock->Alloc()) {
delete newsock;
return (Socket *) GUSI_error_nil(ENOMEM);
}
newsock->HellHoundsOnMyTrail();
if (address && addrlen)
getpeername(address, addrlen);
pb.ppc.informParam.autoAccept = true;
pb.ppc.informParam.portName = &peerPort;
pb.ppc.informParam.locationName = &peerLoc;
pb.ppc.informParam.userName = nil;
PPCInformAsync(&pb.ppc.informParam);
return newsock;
}
int PPCSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
{
long len = buflen;
if (from)
getpeername(from, fromlen);
if (flags)
return GUSI_error(EOPNOTSUPP);
switch(status) {
case PPCSocket::isAccepted:
case PPCSocket::isOpen:
break;
default:
return GUSI_error(ENOTCONN);
}
if (!rb->Valid())
if (readShutDown)
return 0;
else if (nonblocking)
return GUSI_error(EWOULDBLOCK);
else
SPIN(!rb->Valid(), SP_STREAM_READ, 0);
rb->Consume(Ptr(buffer), len);
return len;
}
int PPCSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
{
long len = buflen;
long done = 0;
if (to)
return GUSI_error(EOPNOTSUPP);
if (flags)
return GUSI_error(EOPNOTSUPP);
switch(status) {
case PPCSocket::isAccepted:
case PPCSocket::isOpen:
break;
default:
return GUSI_error(ENOTCONN);
}
if (writeShutDown)
return GUSI_error(ESHUTDOWN);
if (!wb->Free())
if (nonblocking)
return GUSI_error(EWOULDBLOCK);
for (;;) {
wb->Produce(Ptr(buffer), len);
done += len;
if (nonblocking)
break;
buflen -= int(len);
if (!buflen)
break;
buffer = Ptr(buffer) + len;
len = buflen;
SPIN(!wb->Free(), SP_STREAM_WRITE, 0);
}
return done;
}
int PPCSocket::shutdown(int how)
{
if (how < 0 || how > 2)
return GUSI_error(EINVAL);
if (how)
writeShutDown = true;
if (!(how & 1))
readShutDown = true;
return 0;
}
int PPCSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
{
int goodies = 0;
if (canRead)
switch (status) {
case PPCSocket::isListening:
if (pb.ppc.informParam.ioResult != 1) {
*canRead = true;
++goodies;
}
break;
case PPCSocket::isAccepted:
case PPCSocket::isOpen:
if (rb->Valid() || readShutDown) {
*canRead = true;
++goodies;
}
break;
default:
*canRead = true;
++goodies;
break;
}
if (canWrite)
switch (status) {
case PPCSocket::isAccepted:
case PPCSocket::isOpen:
if (wb->Free()) {
*canWrite = true;
++goodies;
}
break;
default:
*canWrite = true;
++goodies;
break;
}
return goodies;
}
/********************* PPCSocketDomain member **********************/
extern "C" void GUSIwithPPCSockets()
{
PPCSockets.DontStrip();
}
PPCSocketDomain::PPCSocketDomain()
: SocketDomain(AF_PPC)
{
}
Socket * PPCSocketDomain::socket(int type, short)
{
PPCSocket * sock = nil;
errno = 0;
if (!hasPPC)
GUSI_error(EOPNOTSUPP);
else
switch (type) {
case SOCK_STREAM:
sock = new PPCSocket();
break;
default:
GUSI_error(ESOCKTNOSUPPORT);
}
if (sock && errno) {
delete sock;
return nil;
} else
return sock;
}
static sa_constr_ppc * CurConstr;
static pascal Boolean GUSIBrowseFilter(LocationNamePtr, PortInfoPtr port)
{
if (CurConstr->flags & PPC_CON_MATCH_NAME)
if (PLstrcmp(port->name.name, CurConstr->match.name))
return false;
if (CurConstr->flags & PPC_CON_MATCH_TYPE)
if (port->name.portKindSelector != ppcByString || PLstrcmp(port->name.u.portTypeStr, CurConstr->match.u.portTypeStr))
return false;
return true;
}
#if GENERATINGCFM
RoutineDescriptor uGUSIBrowseFilter =
BUILD_ROUTINE_DESCRIPTOR(uppPPCFilterProcInfo, GUSIBrowseFilter);
#else
#define uGUSIBrowseFilter GUSIBrowseFilter
#endif
int PPCSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
{
sockaddr_ppc addr;
Str255 promp;
StringPtr nbp = nil;
PortInfoRec info;
static sa_constr_ppc constr;
if (flags & (CHOOSE_NEW | CHOOSE_DIR))
return GUSI_error(EINVAL);
CopyC2PStr(prompt, promp);
CurConstr= (sa_constr_ppc *) constraint;
if (!CurConstr || !(CurConstr->flags & PPC_CON_NEWSTYLE)) {
if (CurConstr && ((char *) constraint)[0]) {
constr.flags = PPC_CON_NEWSTYLE + PPC_CON_MATCH_NBP;
nbp = StringPtr(constraint);
} else
constr.flags = PPC_CON_NEWSTYLE;
CurConstr = &constr;
} else if (CurConstr->flags & PPC_CON_MATCH_NBP)
nbp = CurConstr->nbpType;
if (
PPCBrowser(
promp,
(StringPtr) "\p",
false,
&addr.location,
&info,
(CurConstr->flags & (PPC_CON_MATCH_NAME | PPC_CON_MATCH_TYPE)) ? PPCFilterUPP(&uGUSIBrowseFilter) : PPCFilterUPP(nil),
nbp ? nbp : (StringPtr) "\pPPCToolBox")
)
return GUSI_error(EINTR);
addr.family = AF_PPC;
addr.port = info.name;
memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(sockaddr_ppc))));
return 0;
}